Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ECO-5132] Added typing tests #217

Open
wants to merge 1 commit into
base: 114-tests
Choose a base branch
from
Open

[ECO-5132] Added typing tests #217

wants to merge 1 commit into from

Conversation

maratal
Copy link
Collaborator

@maratal maratal commented Jan 19, 2025

Closes #140

Summary by CodeRabbit

  • New Features

    • Added configurable retry duration for presence retrieval operations.
    • Enhanced typing event testing capabilities.
  • Tests

    • Added comprehensive unit tests for typing indicators and presence events.
    • Introduced new test scenarios for various typing functionalities.
    • Added helper method for approximate double comparison.
  • Improvements

    • Updated initializer to allow custom retry duration.
    • Improved error handling and retry mechanisms.

Copy link

coderabbitai bot commented Jan 19, 2025

Walkthrough

The pull request introduces enhancements to the typing indicators functionality in the AblyChat framework. The changes focus on improving the DefaultTyping class by adding a configurable retry duration for presence retrieval and introducing new testing capabilities. A comprehensive set of unit tests has been added to validate various scenarios related to typing events, including handling attachment states, error conditions, and presence retrieval mechanisms.

Changes

File Change Summary
Sources/AblyChat/DefaultTyping.swift - Added maxPresenceGetRetryDuration property
- Updated initializer to accept retry duration
- Added test-specific methods and TestTypingEvent struct
Tests/AblyChatTests/DefaultRoomTypingTests.swift - Added comprehensive unit tests for typing indicators
- Covered scenarios like client typing, attachment states, error handling, and presence retrieval
Tests/AblyChatTests/Helpers/Helpers.swift - Added isEqual(to:tolerance:) method to Double extension for approximate value comparison

Assessment against linked issues

Objective Addressed Explanation
Add unit tests for typing indicators [#140, ECO-5132]

Possibly related PRs

Suggested reviewers

  • umair-ably
  • lawrence-forooghian

Poem

🐰 In the realm of typing's swift dance,

Code hops with a configurable glance,

Retry durations now flex and sway,

Testing events find their playful way,

A rabbit's code, both nimble and bright! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot temporarily deployed to staging/pull/217/AblyChat January 19, 2025 12:32 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
Sources/AblyChat/DefaultTyping.swift (2)

9-9: Fix typo in property name.

The property name contains a typo: "Presense" should be "Presence".

-    private let maxPresenseGetRetryDuration: TimeInterval // Max duration as specified in CHA-T6c1
+    private let maxPresenceGetRetryDuration: TimeInterval // Max duration as specified in CHA-T6c1

242-252: Prevent memory leaks in test subscriptions.

The test subscription arrays can grow indefinitely as new subscriptions are added. Consider adding cleanup logic to remove terminated subscriptions.

Add a method to clean up terminated subscriptions:

private func cleanupTerminatedSubscriptions() {
    testStartTypingEventSubscriptions.removeAll(where: { $0.isTerminated })
    testStopTypingEventSubscriptions.removeAll(where: { $0.isTerminated })
    testPresenceGetTypingEventSubscriptions.removeAll(where: { $0.isTerminated })
    testPresenceGetRetryTypingEventSubscriptions.removeAll(where: { $0.isTerminated })
}

Call this method before adding new subscriptions in each testsOnly_subscribeTo* method.

Tests/AblyChatTests/DefaultRoomTypingTests.swift (3)

298-298: Implement missing test for CHA-T6c2 specification.

The test ifMultiplePresenceEventsReceivedThenOnlyTheLatestEventIsEmitted is currently unimplemented.

Would you like me to help implement this test case? I can provide a complete implementation that verifies only the latest event is emitted when multiple presence events are received.


268-268: Document the rationale for the arbitrary timeout value.

The comment mentions the timeout value is arbitrary and references an issue. Consider adding more context about why this specific value was chosen.

-        let maxPresenseGetRetryDuration = 3.0 // arbitrary, TODO: improve https://github.com/ably/ably-chat-swift/issues/216
+        let maxPresenseGetRetryDuration = 3.0 // Chosen to balance between quick test execution and reliable presence get retries
+        // TODO: Make this configurable or determine dynamically - https://github.com/ably/ably-chat-swift/issues/216

133-134: Extract magic numbers into named constants.

The timeout value of 0.5 seconds is hardcoded without explanation. Consider extracting this and other similar values into named constants with clear documentation.

+        // Default timeout is 5 seconds, using 0.5 for faster test execution
+        private static let testTimeout: TimeInterval = 0.5
+
-        let timeout = 0.5 // default is 5 (seconds)
+        let timeout = Self.testTimeout
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 371eabd and 612bbc8.

📒 Files selected for processing (3)
  • Sources/AblyChat/DefaultTyping.swift (5 hunks)
  • Tests/AblyChatTests/DefaultRoomTypingTests.swift (1 hunks)
  • Tests/AblyChatTests/Helpers/Helpers.swift (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: Example app, tvOS (Xcode 16)
  • GitHub Check: Example app, iOS (Xcode 16)
  • GitHub Check: Example app, macOS (Xcode 16)
  • GitHub Check: Xcode, tvOS (Xcode 16)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 16)
  • GitHub Check: Xcode, iOS (Xcode 16)
  • GitHub Check: SPM, release configuration (Xcode 16)
  • GitHub Check: SPM (Xcode 16)
  • GitHub Check: Xcode, release configuration, iOS (Xcode 16)
  • GitHub Check: Xcode, macOS (Xcode 16)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 16)
  • GitHub Check: Xcode, tvOS (Xcode 16)
🔇 Additional comments (1)
Sources/AblyChat/DefaultTyping.swift (1)

Line range hint 43-82: Consider potential race condition in presence get retry logic.

The retry logic uses a shared totalElapsedTime variable that could be affected by concurrent presence get operations. Consider using a dedicated task for managing retries.

Consider refactoring the retry logic into a dedicated async task that can be cancelled when needed. This would help prevent race conditions and make the retry state more manageable.

Tests/AblyChatTests/Helpers/Helpers.swift Show resolved Hide resolved
@maratal maratal force-pushed the 114-tests branch 4 times, most recently from ddb3e18 to 3fdad4d Compare January 19, 2025 18:37
@github-actions github-actions bot temporarily deployed to staging/pull/217/AblyChat January 19, 2025 18:41 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
Sources/AblyChat/DefaultTyping.swift (1)

Line range hint 43-82: Ensure Retry Logic Correctly Respects Maximum Retry Duration

In the retry loop for presence.get(), verify that the totalElapsedTime calculation correctly accounts for the delays, including jitter, and that the loop exits after reaching maxPresenceGetRetryDuration.

Review and adjust the calculation of totalElapsedTime to ensure it accurately reflects the accumulated wait times. This ensures the retry mechanism adheres to the specified maximum duration.

🧹 Nitpick comments (7)
Tests/AblyChatTests/DefaultRoomTypingTests.swift (6)

25-52: Ensure Proper Synchronization When Testing Attachment State

In retrieveCurrentlyTypingClientIDsWhileAttaching(), the test sets up an attaching state and waits for the room to become attaching before calling defaultTyping.get(). To prevent flaky tests, ensure that the test reliably waits for the expected state.

Consider adding explicit synchronization or wait mechanisms to ensure the room status is in the attaching state before proceeding. This can improve the reliability of the test.


122-149: Potential Race Condition in Timing-Sensitive Test

In usersMayConfigureTimeoutForTyping(), the test checks if the typing stopped event is emitted after a custom timeout interval. Timing-based tests can lead to flaky results due to execution environment variability.

Consider using mock timers or expectations to control the timing more deterministically. This approach can enhance the reliability of the test across different environments.


194-217: Adjust Tolerance for Timing Comparison

In ifTypingIsAlreadyInProgressThenTimeoutIsExtended(), the test compares intervals using a tolerance of 0.1. Due to potential execution speed variations, consider increasing the tolerance to prevent intermittent test failures.

Adjust the tolerance value to a higher number, such as 0.2, or utilize mock timers for better reliability in timing comparisons.


241-259: Ensure Proper Cleanup of Subscriptions in Tests

In whenPresenceEventReceivedClientWillPerformPresenceGet(), verify that any subscriptions or event listeners are properly cleaned up after the test to prevent side effects on other tests.

Add code to unsubscribe or cancel any ongoing subscriptions at the end of the test. This practice ensures test isolation and reliability.


263-293: Assist with Implementing the Presence Get Retry Test

The test ifPresenceGetFailsItShallBeRetriedUsingBackoffWithJitter() includes a TODO comment referencing issue #216.

Would you like assistance in implementing this test case? I can help draft the test code or provide guidance on handling the retry logic with backoff and jitter.


297-300: Complete the Test Implementation for Multiple Presence Events

The test ifMultiplePresenceEventsReceivedThenOnlyTheLatestEventIsEmitted() is marked as TODO.

Do you need help in implementing this test? I can assist in writing the test code to verify that only the latest typing event is emitted when multiple presence events are received.

Sources/AblyChat/DefaultTyping.swift (1)

236-282: Organize Test-Only Code for Better Maintainability

The test-only code under #if DEBUG includes several subscription methods and structures. For improved maintainability, consider organizing these methods together and providing clear documentation of their purpose.

Grouping the test-only code into an extension or a separate file (if appropriate) can enhance code readability and maintenance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 612bbc8 and 5466b2f.

📒 Files selected for processing (3)
  • Sources/AblyChat/DefaultTyping.swift (5 hunks)
  • Tests/AblyChatTests/DefaultRoomTypingTests.swift (1 hunks)
  • Tests/AblyChatTests/Helpers/Helpers.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Tests/AblyChatTests/Helpers/Helpers.swift
⏰ Context from checks skipped due to timeout of 90000ms (11)
  • GitHub Check: Example app, tvOS (Xcode 16)
  • GitHub Check: Xcode, tvOS (Xcode 16)
  • GitHub Check: Example app, iOS (Xcode 16)
  • GitHub Check: Xcode, iOS (Xcode 16)
  • GitHub Check: Example app, macOS (Xcode 16)
  • GitHub Check: Xcode, macOS (Xcode 16)
  • GitHub Check: SPM (Xcode 16)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 16)
  • GitHub Check: Xcode, release configuration, iOS (Xcode 16)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 16)
  • GitHub Check: SPM, release configuration (Xcode 16)
🔇 Additional comments (9)
Tests/AblyChatTests/DefaultRoomTypingTests.swift (5)

9-21: Good Coverage for Retrieving Typing Client IDs

The test retrieveCurrentlyTypingClientIDs() correctly verifies that the defaultTyping.get() method retrieves the list of currently typing client IDs. The use of mock presence with predefined members ensures the test is reliable and effective.


56-95: Accurate Error Handling in Failure Scenarios

The test retrieveCurrentlyTypingClientIDsWhileAttachingWithFailure() correctly handles exceptions when attachment fails. The error handling in lines 82~ to 91~ captures and asserts the expected status code and error code appropriately.


97-118: Proper Validation of Error Handling When Room Is in Invalid State

The test failToRetrieveCurrentlyTypingClientIDsWhenRoomInInvalidState() effectively verifies that an error is thrown when attempting to retrieve typing client IDs while the room is in an invalid state. The assertions correctly check for the expected error conditions.


156-189: Effective Testing of Start and Stop Typing Indicators

The test usersMayIndicateThatTheyHaveStartedOrStoppedTyping() effectively verifies that the typing indicators work as expected when starting and stopping typing. The assertions confirm that the typing client IDs are correctly updated.


221-237: Comprehensive Test for Subscribing to Typing Events

The test usersMaySubscribeToTypingEvents() successfully verifies that subscribing to typing events works and that the correct data is received. The use of subscriptions ensures that typing events are emitted and captured as expected.

Sources/AblyChat/DefaultTyping.swift (4)

12-18: Configurable maxPresenceGetRetryDuration in Initializer

The initializer for DefaultTyping now accepts the maxPresenceGetRetryDuration parameter with a default value of 30.0. This change enhances configurability and allows for better control over the retry mechanism.


75-79: Proper Emission of Test Events During Retry Attempts

The code under #if DEBUG emits test events during retry attempts. This practice is appropriate for testing purposes.

Ensure that these test-only events are properly guarded and do not impact production code.


173-177: Test Events Emitted When Stopping Typing Indicators

In the stop() method, test events are emitted under #if DEBUG when typing is stopped. This aids in testing the stop functionality.


227-231: Test Events Emitted When Starting Typing Indicators

Similarly, in the startTyping() method, test events are emitted under #if DEBUG when typing starts. This facilitates testing the start functionality.

Sources/AblyChat/DefaultTyping.swift Show resolved Hide resolved
@maratal
Copy link
Collaborator Author

maratal commented Jan 19, 2025

Spec coverage test issue - ably/specification#269

@github-actions github-actions bot temporarily deployed to staging/pull/217/AblyChat January 19, 2025 18:51 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
Sources/AblyChat/DefaultTyping.swift (2)

237-282: Enhance documentation for test-only APIs.

The test infrastructure is well-organized, but the documentation could be more descriptive about the purpose and usage of each subscription type.

Apply this diff to enhance the documentation:

 #if DEBUG
-    /// The `DefaultTyping` emits a `TestTypingEvent` each time ``start`` or ``stop`` is called.
+    /// Represents a typing-related test event with a timestamp.
+    /// Used to track when various typing-related operations occur during testing.
     internal struct TestTypingEvent: Equatable {
         internal let timestamp = Date()
     }

-    /// Subscription of typing start events for testing purposes.
+    /// Collection of subscriptions that receive events when typing starts.
+    /// These events are emitted after successfully entering presence.
     private var testStartTypingEventSubscriptions: [Subscription<TestTypingEvent>] = []

-    /// Subscription of typing stop events for testing purposes.
+    /// Collection of subscriptions that receive events when typing stops.
+    /// These events are emitted after successfully leaving presence.
     private var testStopTypingEventSubscriptions: [Subscription<TestTypingEvent>] = []

-    /// Subscription of presence get events for testing purposes.
+    /// Collection of subscriptions that receive events when presence.get() succeeds.
+    /// These events are emitted after successfully retrieving the presence set.
     private var testPresenceGetTypingEventSubscriptions: [Subscription<TestTypingEvent>] = []

-    /// Subscription of retry presence get events for testing purposes.
+    /// Collection of subscriptions that receive events when presence.get() fails and is retried.
+    /// These events are emitted before each retry attempt.
     private var testPresenceGetRetryTypingEventSubscriptions: [Subscription<TestTypingEvent>] = []

285-287: Document the rationale for @unchecked Sendable conformance.

Add documentation explaining why the conformance is needed and why it's safe to use @unchecked.

Apply this diff:

 #if DEBUG
+/// Conformance to Sendable is required for test-only features.
+/// Using @unchecked because the class contains mutable state that is only accessed
+/// in a controlled manner through test-only methods.
     extension DefaultTyping: @unchecked Sendable {}
 #endif
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5466b2f and 3e11ea0.

📒 Files selected for processing (3)
  • Sources/AblyChat/DefaultTyping.swift (5 hunks)
  • Tests/AblyChatTests/DefaultRoomTypingTests.swift (1 hunks)
  • Tests/AblyChatTests/Helpers/Helpers.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Tests/AblyChatTests/Helpers/Helpers.swift
  • Tests/AblyChatTests/DefaultRoomTypingTests.swift
🔇 Additional comments (4)
Sources/AblyChat/DefaultTyping.swift (4)

9-9: Fix typo in property name and enhance documentation.

The property name has a typo: "Presense" should be "Presence". Additionally, consider adding more descriptive documentation using Swift's documentation comments.

Apply this diff:

-private let maxPresenceGetRetryDuration: TimeInterval // Max duration as specified in CHA-T6c1
+/// Maximum duration to retry presence get operations when they fail.
+/// Specification: CHA-T6c1
+private let maxPresenceGetRetryDuration: TimeInterval

Line range hint 43-82: LGTM! Well-implemented retry mechanism.

The retry logic is well-implemented with:

  • Configurable maximum retry duration
  • Exponential backoff with jitter
  • Clear error logging
  • Proper test instrumentation

173-177: LGTM! Test instrumentation properly added.

Test event emission is correctly placed after the presence leave operation and properly guarded with DEBUG flag.


227-231: LGTM! Test instrumentation properly added.

Test event emission is correctly placed after the timer setup and properly guarded with DEBUG flag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant